/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/05/20
* File: Octree.h
* Blog: http://www.cnblogs.com/zengqh/
**/

#pragma once

#include <math/math.h>

namespace HY
{
class SceneNode;
class OctreeNode
{
public:
	typedef SceneNode					ObjectType;
	typedef std::set<ObjectType*>		ObjectList;

public:
	OctreeNode();
	~OctreeNode();

public:
	void addObject( ObjectType* obj );
	void removeObject( ObjectType* obj );
	void removeAllObjects();

	bool selfCanHold( const BoundingBox &box, bool ignoreSize ) const;
	bool childCanHoldBySize( const BoundingBox &box ) const;
	void getChildIndexes( const BoundingBox &box, int *x, int *y, int *z ) const;

	void setBoundBox( const BoundingBox& box );
	void setBoundBox( const Vector3& vmin, const Vector3& vmax );

	const BoundingBox& getBoundBox() const { return box_; }
	const BoundingBox& getCullBoundBox() const { return box_cull_; }

private:
	void _updateCullBoundBox();

public:
	OctreeNode*		parent_;
	union
	{
		OctreeNode* child_list_[8];
		OctreeNode* child_[2][2][2];
	};

	ObjectList	obj_list_;

protected:
	BoundingBox		box_;
	BoundingBox		box_cull_;
};

class Octree
{
public:
	typedef OctreeNode::ObjectType ObjectType;
public:
	Octree();
	~Octree();

public:
	void init( const BoundingBox& box, int maxDepth );
	void clear();

	void updateMaxDepth( int maxDepth );
	void updateBox( const BoundingBox& box );
	void updateObject( ObjectType* obj );

protected:
	void _addObjectToNode( OctreeNode* node, ObjectType* obj, int depth );
	void _removeObjectFromNode( ObjectType* obj );
public:
	OctreeNode*		root_;
	int				max_depth_;
};

}